package rules

import (
	v1 "golang-sgg-daijia/api/v1"
	"math"
	"time"
)

// FeeRuleImplement 计算费用
type FeeRuleImplement struct {
}

func NewFeeRuleImplement() *FeeRuleImplement {
	return &FeeRuleImplement{}
}

// CalculateAllFee 计算费用的步骤
func (f *FeeRuleImplement) CalculateAllFee(feeRuleReq *v1.FeeRuleRequestForm) *v1.FeeRuleResponse {
	resp := new(v1.FeeRuleResponse)
	startTime := feeRuleReq.StartTime
	// todo 由注册的方式串联起来
	// CalculateAllFee 1. 起步价
	newStartFeeRule(startTime).CalculateFee(feeRuleReq, resp)
	// DistanceFee 2. 里程费
	newDistanceFeeRule(startTime, feeRuleReq.Distance).CalculateFee(feeRuleReq, resp)
	// WaitFee 3.等候费
	newWaitFeeRule(feeRuleReq.WaitMinute).CalculateFee(feeRuleReq, resp)
	// LongDistanceFee 4. 远途费
	newLongDistanceFeeRule(feeRuleReq.Distance).CalculateFee(feeRuleReq, resp)
	// TotalFee 5. 总金额
	newTotalFeeRule().CalculateFee(feeRuleReq, resp)
	return resp
}

type FeeRule interface {
	CalculateFee(feeRuleReq *v1.FeeRuleRequestForm, feeRuleResp *v1.FeeRuleResponse)
}

func newStartFeeRule(workTime time.Time) FeeRule {
	nightBegin := time.Date(workTime.Year(), workTime.Month(), workTime.Day(), 0, 0, 0, 0, time.Local)
	nightEnd := time.Date(workTime.Year(), workTime.Month(), workTime.Day(), 7, 0, 0, 0, time.Local)
	if workTime.After(nightBegin) && workTime.Before(nightEnd) {
		return &nightStartFreeRule{}
	}
	return &dayStartFreeRule{}
}

type nightStartFreeRule struct{}

func (s *nightStartFreeRule) CalculateFee(feeRuleReq *v1.FeeRuleRequestForm, feeRuleResp *v1.FeeRuleResponse) {
	// 晚上的起步价
	//基础里程 3公里
	feeRuleResp.BaseDistance = 3.0
	//收费19元 础里程费
	feeRuleResp.BaseDistanceFee = 19.0
	feeRuleResp.ExceedDistance = 0.0
	feeRuleResp.ExceedDistancePrice = 4.0
}

type dayStartFreeRule struct{}

func (s *dayStartFreeRule) CalculateFee(feeRuleReq *v1.FeeRuleRequestForm, feeRuleResp *v1.FeeRuleResponse) {
	// 白天的起步价
	//基础里程 3公里
	feeRuleResp.BaseDistance = 5.0
	//收费19元 础里程费
	feeRuleResp.BaseDistanceFee = 19.0
	feeRuleResp.ExceedDistance = 0.0
	feeRuleResp.ExceedDistancePrice = 3.0
}

func newDistanceFeeRule(workTime time.Time, distance float64) FeeRule {
	nightBegin := time.Date(workTime.Year(), workTime.Month(), workTime.Day(), 0, 0, 0, 0, time.Local)
	nightEnd := time.Date(workTime.Year(), workTime.Month(), workTime.Day(), 7, 0, 0, 0, time.Local)
	dayEnd := time.Date(workTime.Year(), workTime.Month(), workTime.Day(), 23, 59, 59, 0, time.Local)
	if workTime.After(nightBegin) && workTime.Before(nightEnd) && distance > 3.0 {
		return &nightDistanceFeeRule{}
	} else if workTime.After(nightEnd) && workTime.Before(dayEnd) && distance > 5.0 {
		return &dayDistanceFeeRule{}
	}
	return &defaultDistanceFeeRule{}
}

type nightDistanceFeeRule struct{}

func (s *nightDistanceFeeRule) CalculateFee(feeRuleReq *v1.FeeRuleRequestForm, feeRuleResp *v1.FeeRuleResponse) {
	// 晚上的里程费
	feeRuleResp.ExceedDistance = feeRuleReq.Distance - 3.0
	feeRuleResp.ExceedDistancePrice = 4.0
}

type dayDistanceFeeRule struct{}

func (s *dayDistanceFeeRule) CalculateFee(feeRuleReq *v1.FeeRuleRequestForm, feeRuleResp *v1.FeeRuleResponse) {
	// 白天的里程费
	feeRuleResp.ExceedDistance = feeRuleReq.Distance - 5.0
	feeRuleResp.ExceedDistancePrice = 3.0
}

type defaultDistanceFeeRule struct {
}

func (s *defaultDistanceFeeRule) CalculateFee(feeRuleReq *v1.FeeRuleRequestForm, feeRuleResp *v1.FeeRuleResponse) {
	// 默认里程费计算逻辑，默认无里程费
}


func newWaitFeeRule(waitMinute int) FeeRule {
	if waitMinute > 10 {
		return &baseWaitFeeRule{}
	}
	return &withoutWaitFeeRule{}
}

type baseWaitFeeRule struct{}

func (s *baseWaitFeeRule) CalculateFee(feeRuleReq *v1.FeeRuleRequestForm, feeRuleResp *v1.FeeRuleResponse) {
	// 等候费
	feeRuleResp.BaseWaitMinute = 10
	feeRuleResp.ExceedWaitMinute = feeRuleReq.WaitMinute - 10
	feeRuleResp.ExceedWaitMinutePrice = 1.0
}

type withoutWaitFeeRule struct{}

func (s *withoutWaitFeeRule) CalculateFee(feeRuleReq *v1.FeeRuleRequestForm, feeRuleResp *v1.FeeRuleResponse) {
	// 无等待费
	feeRuleResp.BaseWaitMinute = 10
	feeRuleResp.ExceedWaitMinute = 0
	feeRuleResp.ExceedWaitMinutePrice = 1.0
}

func newLongDistanceFeeRule(distance float64) FeeRule {
	if distance > 12 {
		return &baseLongDistanceFeeRule{}
	}
	return &withoutLongDistanceFeeRule{}
}

type baseLongDistanceFeeRule struct{}

func (s *baseLongDistanceFeeRule) CalculateFee(feeRuleReq *v1.FeeRuleRequestForm, feeRuleResp *v1.FeeRuleResponse) {
	// 远途费
	feeRuleResp.BaseLongDistance = 12.0
	feeRuleResp.ExceedLongDistance = feeRuleReq.Distance - 12.0
	feeRuleResp.ExceedLongDistancePrice = 1.0
}

type withoutLongDistanceFeeRule struct{}

func (s *withoutLongDistanceFeeRule) CalculateFee(feeRuleReq *v1.FeeRuleRequestForm, feeRuleResp *v1.FeeRuleResponse) {
	// 无远途费
	feeRuleResp.BaseLongDistance = 12.0
	feeRuleResp.ExceedLongDistance = 0
	feeRuleResp.ExceedLongDistancePrice = 0
}

func newTotalFeeRule() FeeRule {
	return &totalFeeRule{}
}

type totalFeeRule struct{}

func (s *totalFeeRule) CalculateFee(feeRuleReq *v1.FeeRuleRequestForm, feeRuleResp *v1.FeeRuleResponse) {
	// 总金额
	// 订单总金额 = 基础里程费 + 超出基础里程的费 + 等候费 + 远程费
	distanceFee := feeRuleResp.BaseDistanceFee + feeRuleResp.ExceedDistancePrice*feeRuleResp.ExceedDistance
	waitFee := feeRuleResp.ExceedWaitMinutePrice * float64(feeRuleResp.ExceedWaitMinute)
	longDistanceFee := feeRuleResp.ExceedLongDistancePrice * feeRuleResp.ExceedLongDistance

	feeRuleResp.TotalAmount = math.Round((distanceFee + waitFee + longDistanceFee) * 100) / 100
	feeRuleResp.WaitFee = waitFee
	feeRuleResp.LongDistanceFee = longDistanceFee
	feeRuleResp.DistanceFee = distanceFee
}
